package services

import (
	"fmt"
	"io"
	"log"
	"strings"
	"time"

	"github.com/gophercloud/gophercloud"
	"github.com/gophercloud/gophercloud/openstack"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/domains"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/projects"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/roles"
	"github.com/gophercloud/gophercloud/openstack/identity/v3/users"
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/containers"
	"github.com/gophercloud/gophercloud/openstack/objectstorage/v1/objects"
)

type SwiftService struct {
	client         *gophercloud.ServiceClient
	provider       *gophercloud.ProviderClient
	identityClient *gophercloud.ServiceClient
}

type ContainerInfo struct {
	Name         string    `json:"name"`
	Count        int64     `json:"count"`
	Bytes        int64     `json:"bytes"`
	LastModified time.Time `json:"last_modified"`
}

type ObjectInfo struct {
	Name         string    `json:"name"`
	Bytes        int64     `json:"bytes"`
	ContentType  string    `json:"content_type"`
	LastModified time.Time `json:"last_modified"`
	ETag         string    `json:"etag"`
}

type ConfigValidationError struct {
	Type    string `json:"type"`
	Message string `json:"message"`
	Fix     string `json:"fix"`
}

type ValidationResult struct {
	Valid  bool                    `json:"valid"`
	Errors []ConfigValidationError `json:"errors"`
}

func NewSwiftService(authURL, username, password, projectName, domainName string) (*SwiftService, error) {
	// 检查是否使用admin用户，禁止使用
	if strings.ToLower(username) == "admin" {
		return nil, fmt.Errorf("安全检查失败: 禁止使用admin用户进行Swift操作，请使用专用的Swift服务用户")
	}

	authOptions := gophercloud.AuthOptions{
		IdentityEndpoint: authURL,
		Username:         username,
		Password:         password,
		TenantName:       projectName,
		DomainName:       domainName,
	}

	provider, err := openstack.AuthenticatedClient(authOptions)
	if err != nil {
		return nil, fmt.Errorf("Swift认证失败: %v", err)
	}

	client, err := openstack.NewObjectStorageV1(provider, gophercloud.EndpointOpts{
		Region: "RegionOne",
	})
	if err != nil {
		return nil, fmt.Errorf("创建Swift客户端失败: %v", err)
	}

	identityClient, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{
		Region: "RegionOne",
	})
	if err != nil {
		return nil, fmt.Errorf("创建Identity客户端失败: %v", err)
	}

	return &SwiftService{
		client:         client,
		provider:       provider,
		identityClient: identityClient,
	}, nil
}

// 使用应用凭证创建Swift服务
func NewSwiftServiceWithAppCredential(authURL, appCredID, appCredSecret string) (*SwiftService, error) {
	authOptions := gophercloud.AuthOptions{
		IdentityEndpoint:            authURL,
		ApplicationCredentialID:     appCredID,
		ApplicationCredentialSecret: appCredSecret,
	}

	provider, err := openstack.AuthenticatedClient(authOptions)
	if err != nil {
		return nil, fmt.Errorf("应用凭证认证失败: %v", err)
	}

	client, err := openstack.NewObjectStorageV1(provider, gophercloud.EndpointOpts{
		Region: "RegionOne",
	})
	if err != nil {
		return nil, fmt.Errorf("创建Swift客户端失败: %v", err)
	}

	identityClient, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{
		Region: "RegionOne",
	})
	if err != nil {
		return nil, fmt.Errorf("创建Identity客户端失败: %v", err)
	}

	return &SwiftService{
		client:         client,
		provider:       provider,
		identityClient: identityClient,
	}, nil
}

func (s *SwiftService) ValidateConfiguration(config map[string]interface{}) ValidationResult {
	var errors []ConfigValidationError

	// 验证容器
	if errs := s.validateContainers(config); len(errs) > 0 {
		errors = append(errors, errs...)
	}

	// 验证连接
	if err := s.validateConnection(); err != nil {
		errors = append(errors, *err)
	}

	return ValidationResult{
		Valid:  len(errors) == 0,
		Errors: errors,
	}
}

func (s *SwiftService) validateContainers(config map[string]interface{}) []ConfigValidationError {
	var errors []ConfigValidationError

	storageConfig := config["storage"].(map[string]interface{})
	containerList := storageConfig["containers"].([]interface{})

	for _, containerConfig := range containerList {
		containerData := containerConfig.(map[string]interface{})
		containerName := containerData["name"].(string)

		exists, err := s.ContainerExists(containerName)
		if err != nil {
			errors = append(errors, ConfigValidationError{
				Type:    "container_query_error",
				Message: fmt.Sprintf("无法查询容器 '%s': %v", containerName, err),
				Fix:     "请检查Swift连接配置和权限",
			})
			continue
		}

		if !exists {
			errors = append(errors, ConfigValidationError{
				Type:    "container_missing",
				Message: fmt.Sprintf("容器 '%s' 不存在", containerName),
				Fix:     fmt.Sprintf("openstack container create %s", containerName),
			})
		} else {
			log.Printf("✓ 检查容器 '%s' ... 存在", containerName)
		}
	}

	return errors
}

func (s *SwiftService) validateConnection() *ConfigValidationError {
	// 尝试列出容器来验证连接
	_, err := s.ListContainers()
	if err != nil {
		return &ConfigValidationError{
			Type:    "connection_error",
			Message: fmt.Sprintf("Swift连接测试失败: %v", err),
			Fix:     "请检查auth_url、用户凭证和Swift服务状态",
		}
	}

	log.Printf("✓ Swift服务连接正常")
	return nil
}

func (s *SwiftService) ContainerExists(containerName string) (bool, error) {
	allPages, err := containers.List(s.client, &containers.ListOpts{}).AllPages()
	if err != nil {
		return false, err
	}

	containerList, err := containers.ExtractNames(allPages)
	if err != nil {
		return false, err
	}

	for _, name := range containerList {
		if name == containerName {
			return true, nil
		}
	}

	return false, nil
}

func (s *SwiftService) ListContainers() ([]ContainerInfo, error) {
	allPages, err := containers.List(s.client, &containers.ListOpts{
		Format: "json",
	}).AllPages()
	if err != nil {
		return nil, err
	}

	containerList, err := containers.ExtractInfo(allPages)
	if err != nil {
		return nil, err
	}

	result := make([]ContainerInfo, len(containerList))
	for i, container := range containerList {
		result[i] = ContainerInfo{
			Name:         container.Name,
			Count:        container.Count,
			Bytes:        container.Bytes,
			LastModified: time.Now(),
		}
	}

	return result, nil
}

func (s *SwiftService) ListObjects(containerName string) ([]ObjectInfo, error) {
	allPages, err := objects.List(s.client, containerName, &objects.ListOpts{
		Format: "json",
	}).AllPages()
	if err != nil {
		return nil, err
	}

	objectList, err := objects.ExtractInfo(allPages)
	if err != nil {
		return nil, err
	}

	result := make([]ObjectInfo, len(objectList))
	for i, obj := range objectList {
		result[i] = ObjectInfo{
			Name:         obj.Name,
			Bytes:        obj.Bytes,
			ContentType:  obj.ContentType,
			LastModified: obj.LastModified,
			ETag:         obj.Hash,
		}
	}

	return result, nil
}

func (s *SwiftService) UploadObject(containerName, objectName string, content io.Reader, contentType string) error {
	createOpts := objects.CreateOpts{
		Content:     content,
		ContentType: contentType,
	}

	result := objects.Create(s.client, containerName, objectName, createOpts)
	if result.Err != nil {
		return fmt.Errorf("上传对象失败: %v", result.Err)
	}

	log.Printf("✓ 对象 '%s' 上传到容器 '%s' 成功", objectName, containerName)
	return nil
}

func (s *SwiftService) DownloadObject(containerName, objectName string) (io.ReadCloser, error) {
	result := objects.Download(s.client, containerName, objectName, nil)
	if result.Err != nil {
		return nil, fmt.Errorf("下载对象失败: %v", result.Err)
	}

	return result.Body, nil
}

func (s *SwiftService) DeleteObject(containerName, objectName string) error {
	result := objects.Delete(s.client, containerName, objectName, nil)
	if result.Err != nil {
		return fmt.Errorf("删除对象失败: %v", result.Err)
	}

	log.Printf("✓ 对象 '%s' 从容器 '%s' 删除成功", objectName, containerName)
	return nil
}

func (s *SwiftService) GetObjectMetadata(containerName, objectName string) (map[string]string, error) {
	result := objects.Get(s.client, containerName, objectName, nil)
	if result.Err != nil {
		return nil, fmt.Errorf("获取对象元数据失败: %v", result.Err)
	}

	headers, err := result.Extract()
	if err != nil {
		return nil, err
	}

	return map[string]string{
		"content-type":   headers.ContentType,
		"content-length": fmt.Sprintf("%d", headers.ContentLength),
		"last-modified":  headers.Date.Format(time.RFC1123),
		"etag":           headers.ETag,
	}, nil
}

func (s *SwiftService) CreateContainer(containerName string) error {
	result := containers.Create(s.client, containerName, nil)
	if result.Err != nil {
		return fmt.Errorf("创建容器失败: %v", result.Err)
	}

	log.Printf("✓ 容器 '%s' 创建成功", containerName)
	return nil
}

// 工具函数
func FormatFileSize(bytes int64) string {
	const unit = 1024
	if bytes < unit {
		return fmt.Sprintf("%d B", bytes)
	}
	div, exp := int64(unit), 0
	for n := bytes / unit; n >= unit; n /= unit {
		div *= unit
		exp++
	}
	return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
}

func GetFileExtension(filename string) string {
	parts := strings.Split(filename, ".")
	if len(parts) > 1 {
		return "." + strings.ToLower(parts[len(parts)-1])
	}
	return ""
}

// 管理员服务 - 用于创建和管理开发用户
type AdminService struct {
	identityClient *gophercloud.ServiceClient
	provider       *gophercloud.ProviderClient
}

func NewAdminService(authURL, username, password, projectName, domainName string) (*AdminService, error) {
	// 必须使用admin用户才能创建其他用户
	if strings.ToLower(username) != "admin" {
		return nil, fmt.Errorf("用户管理服务只能使用admin账号")
	}

	authOptions := gophercloud.AuthOptions{
		IdentityEndpoint: authURL,
		Username:         username,
		Password:         password,
		TenantName:       projectName,
		DomainName:       domainName,
	}

	provider, err := openstack.AuthenticatedClient(authOptions)
	if err != nil {
		return nil, fmt.Errorf("管理员认证失败: %v", err)
	}

	identityClient, err := openstack.NewIdentityV3(provider, gophercloud.EndpointOpts{
		Region: "RegionOne",
	})
	if err != nil {
		return nil, fmt.Errorf("创建Identity客户端失败: %v", err)
	}

	return &AdminService{
		identityClient: identityClient,
		provider:       provider,
	}, nil
}

func (a *AdminService) SetupDevelopmentEnvironment(config map[string]interface{}) ValidationResult {
	var errors []ConfigValidationError

	// 验证并创建企业域和项目
	if err := a.ensureDomainAndProject(config); err != nil {
		errors = append(errors, *err)
	}

	// 验证并创建开发用户
	if errs := a.ensureDeveloperUsers(config); len(errs) > 0 {
		errors = append(errors, errs...)
	}

	// 验证并创建Swift容器
	if errs := a.ensureSwiftContainers(config); len(errs) > 0 {
		errors = append(errors, errs...)
	}

	return ValidationResult{
		Valid:  len(errors) == 0,
		Errors: errors,
	}
}

func (a *AdminService) ensureDomainAndProject(config map[string]interface{}) *ConfigValidationError {
	enterpriseConfig := config["enterprise"].(map[string]interface{})
	domainName := enterpriseConfig["domain_name"].(string)
	projectName := enterpriseConfig["project_name"].(string)

	// 检查域是否存在，不存在则创建
	domainID, err := a.getDomainID(domainName)
	if err != nil {
		log.Printf("创建企业域: %s", domainName)
		if err := a.createDomain(domainName, enterpriseConfig["project_description"].(string)); err != nil {
			return &ConfigValidationError{
				Type:    "domain_creation_failed",
				Message: fmt.Sprintf("创建域失败: %v", err),
				Fix:     fmt.Sprintf("手动执行: openstack domain create %s", domainName),
			}
		}
		domainID, _ = a.getDomainID(domainName)
	}

	// 检查项目是否存在，不存在则创建
	if _, err := a.getProjectID(projectName, domainID); err != nil {
		log.Printf("创建企业项目: %s", projectName)
		if err := a.createProject(projectName, domainID, enterpriseConfig["project_description"].(string)); err != nil {
			return &ConfigValidationError{
				Type:    "project_creation_failed",
				Message: fmt.Sprintf("创建项目失败: %v", err),
				Fix:     fmt.Sprintf("手动执行: openstack project create --domain %s %s", domainName, projectName),
			}
		}
	}

	log.Printf("✓ 企业域和项目配置完成")
	return nil
}

func (a *AdminService) ensureDeveloperUsers(config map[string]interface{}) []ConfigValidationError {
	var errors []ConfigValidationError

	enterpriseConfig := config["enterprise"].(map[string]interface{})
	domainName := enterpriseConfig["domain_name"].(string)
	projectName := enterpriseConfig["project_name"].(string)

	domainID, err := a.getDomainID(domainName)
	if err != nil {
		return []ConfigValidationError{{
			Type:    "domain_not_found",
			Message: fmt.Sprintf("域 %s 不存在", domainName),
			Fix:     "请先创建企业域",
		}}
	}

	projectID, err := a.getProjectID(projectName, domainID)
	if err != nil {
		return []ConfigValidationError{{
			Type:    "project_not_found",
			Message: fmt.Sprintf("项目 %s 不存在", projectName),
			Fix:     "请先创建企业项目",
		}}
	}

	developerUsers := config["developer_users"].(map[string]interface{})

	for userType, userConfig := range developerUsers {
		userData := userConfig.(map[string]interface{})
		username := userData["openstack_username"].(string)
		password := userData["openstack_password"].(string)

		// 检查用户是否存在，不存在则创建
		userID, err := a.getUserID(username, domainID)
		if err != nil {
			log.Printf("为 %s 创建用户: %s", userType, username)
			if err := a.createUser(username, password, domainID, userData["description"].(string)); err != nil {
				errors = append(errors, ConfigValidationError{
					Type:    "user_creation_failed",
					Message: fmt.Sprintf("创建用户 %s 失败: %v", username, err),
					Fix:     fmt.Sprintf("手动执行: openstack user create --domain %s --password %s %s", domainName, password, username),
				})
				continue
			}
			userID, _ = a.getUserID(username, domainID)
		}

		// 分配项目角色
		if err := a.assignProjectRole(userID, projectID, "member"); err != nil {
			errors = append(errors, ConfigValidationError{
				Type:    "role_assignment_failed",
				Message: fmt.Sprintf("为用户 %s 分配角色失败: %v", username, err),
				Fix:     fmt.Sprintf("手动执行: openstack role add --project %s --user %s member", projectName, username),
			})
		} else {
			log.Printf("✓ 用户 %s (%s) 配置完成", username, userType)
		}
	}

	return errors
}

func (a *AdminService) ensureSwiftContainers(config map[string]interface{}) []ConfigValidationError {
	var errors []ConfigValidationError

	// 使用第一个开发用户的凭证创建Swift客户端来管理容器
	developerUsers := config["developer_users"].(map[string]interface{})
	enterpriseConfig := config["enterprise"].(map[string]interface{})

	var swiftService *SwiftService
	for _, userConfig := range developerUsers {
		userData := userConfig.(map[string]interface{})
		authType := userData["auth_type"].(string)

		if authType == "password" {
			swiftService, _ = NewSwiftService(
				config["admin"].(map[string]interface{})["auth_url"].(string),
				userData["openstack_username"].(string),
				userData["openstack_password"].(string),
				enterpriseConfig["project_name"].(string),
				enterpriseConfig["domain_name"].(string),
			)
			break
		}
	}

	if swiftService == nil {
		return []ConfigValidationError{{
			Type:    "swift_client_failed",
			Message: "无法创建Swift客户端用于容器管理",
			Fix:     "请确保至少有一个开发用户使用密码认证",
		}}
	}

	requiredContainers := config["required_containers"].([]interface{})
	for _, containerConfig := range requiredContainers {
		containerData := containerConfig.(map[string]interface{})
		containerName := containerData["name"].(string)

		exists, err := swiftService.ContainerExists(containerName)
		if err != nil {
			errors = append(errors, ConfigValidationError{
				Type:    "container_check_failed",
				Message: fmt.Sprintf("检查容器 %s 失败: %v", containerName, err),
				Fix:     "请检查Swift服务状态和用户权限",
			})
			continue
		}

		if !exists {
			if err := swiftService.CreateContainer(containerName); err != nil {
				errors = append(errors, ConfigValidationError{
					Type:    "container_creation_failed",
					Message: fmt.Sprintf("创建容器 %s 失败: %v", containerName, err),
					Fix:     fmt.Sprintf("手动执行: openstack container create %s", containerName),
				})
			}
		}
	}

	return errors
}

// Identity API 辅助函数
func (a *AdminService) getDomainID(domainName string) (string, error) {
	allPages, err := domains.List(a.identityClient, domains.ListOpts{Name: domainName}).AllPages()
	if err != nil {
		return "", err
	}

	domainList, err := domains.ExtractDomains(allPages)
	if err != nil || len(domainList) == 0 {
		return "", fmt.Errorf("域 %s 不存在", domainName)
	}

	return domainList[0].ID, nil
}

func (a *AdminService) getProjectID(projectName, domainID string) (string, error) {
	allPages, err := projects.List(a.identityClient, projects.ListOpts{
		DomainID: domainID,
		Name:     projectName,
	}).AllPages()
	if err != nil {
		return "", err
	}

	projectList, err := projects.ExtractProjects(allPages)
	if err != nil || len(projectList) == 0 {
		return "", fmt.Errorf("项目 %s 不存在", projectName)
	}

	return projectList[0].ID, nil
}

func (a *AdminService) getUserID(username, domainID string) (string, error) {
	allPages, err := users.List(a.identityClient, users.ListOpts{
		DomainID: domainID,
		Name:     username,
	}).AllPages()
	if err != nil {
		return "", err
	}

	userList, err := users.ExtractUsers(allPages)
	if err != nil || len(userList) == 0 {
		return "", fmt.Errorf("用户 %s 不存在", username)
	}

	return userList[0].ID, nil
}

func (a *AdminService) createDomain(name, description string) error {
	createOpts := domains.CreateOpts{
		Name:        name,
		Description: description,
		Enabled:     gophercloud.Enabled,
	}

	_, err := domains.Create(a.identityClient, createOpts).Extract()
	return err
}

func (a *AdminService) createProject(name, domainID, description string) error {
	createOpts := projects.CreateOpts{
		Name:        name,
		DomainID:    domainID,
		Description: description,
		Enabled:     gophercloud.Enabled,
	}

	_, err := projects.Create(a.identityClient, createOpts).Extract()
	return err
}

func (a *AdminService) createUser(username, password, domainID, description string) error {
	createOpts := users.CreateOpts{
		Name:        username,
		Password:    password,
		DomainID:    domainID,
		Description: description,
		Enabled:     gophercloud.Enabled,
	}

	_, err := users.Create(a.identityClient, createOpts).Extract()
	return err
}

func (a *AdminService) assignProjectRole(userID, projectID, roleName string) error {
	roleID, err := a.getRoleID(roleName)
	if err != nil {
		return err
	}

	return roles.Assign(a.identityClient, roleID, roles.AssignOpts{
		UserID:    userID,
		ProjectID: projectID,
	}).ExtractErr()
}

func (a *AdminService) getRoleID(roleName string) (string, error) {
	allPages, err := roles.List(a.identityClient, roles.ListOpts{Name: roleName}).AllPages()
	if err != nil {
		return "", err
	}

	roleList, err := roles.ExtractRoles(allPages)
	if err != nil || len(roleList) == 0 {
		return "", fmt.Errorf("角色 %s 不存在", roleName)
	}

	return roleList[0].ID, nil
}
